package com.spider.gp.wordUtil;

import fr.opensagres.xdocreport.converter.ConverterTypeTo;
import fr.opensagres.xdocreport.converter.ConverterTypeVia;
import fr.opensagres.xdocreport.converter.Options;
import fr.opensagres.xdocreport.core.document.SyntaxKind;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import fr.opensagres.xdocreport.template.formatter.NullImageBehaviour;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.converter.pdf.PdfConverter;
import org.apache.poi.xwpf.converter.pdf.PdfOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.stereotype.Controller;
import org.springframework.web.util.HtmlUtils;

import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * description:
 *
 * @author clare
 * @date 2022/06/22 17:10
 **/
@Controller
@Slf4j
public class WordController {


    public void wordExport() {
//        makePdfByXcode();
//        makePdfByXcode();
    }

    public void createXdocreport() {
        try {
            //使用远程模板
//            InputStream inputStream =this.getClass().getClassLoader().getResourceAsStream("/测试1.docx");

//            InputStream inputStream = new URL(templateUrl).openConnection().getInputStream();
            File inputPath = new File("G:\\gpnew\\gp\\src\\main\\resources\\测试1.docx");
            FileInputStream inputStream = new FileInputStream(inputPath);
            File outputPath = new File("G:\\gpnew\\gp\\src\\main\\resources\\测试3.docx");
            FileOutputStream outputStream = new FileOutputStream(outputPath);
            IXDocReport report = XDocReportRegistry
                    .getRegistry()
                    .loadReport(inputStream, TemplateEngineKind.Freemarker);
            // 设置特殊字段
            FieldsMetadata metadata = report.createFieldsMetadata();
//            metadata.addFieldAsTextStyling("content", SyntaxKind.Html);
//            metadata.addFieldAsImage("avatar", "user.avatar", NullImageBehaviour.RemoveImageTemplate);
            report.setFieldsMetadata(metadata);
//            // 创建内容-text为模版中对应都变量名称
//            String content = "&#x3c;p&#x3e;我在这里放了一段富文本&#x3c;/p&#x3e;" +
//                    "&#x3c;p&#x3e;我准备测试富文本的处理&#x3c;/p&#x3e;";
//            content = HtmlUtils.htmlUnescape(content);
            IContext context = report.createContext();
            context.put("projectName", "年终总结大会");
            context.put("companyName", "2021年3月26日");
//            context.put("place", "线上");
//            context.put("sponsor", "张三");
//            context.put("content", content);
//            //图片这里放图片的输入流
//            InputStream p1 = new FileInputStream(new File("C:\\Users\\luban\\Desktop\\图片1.png"));
//            InputStream p2 = new FileInputStream(new File("C:\\Users\\luban\\Desktop\\图片2.jpg"));
//            List<UserAvatar> users = Lists.newArrayList(
//                    new UserAvatar("张三", "组织部", new ByteArrayImageProvider(p1)),
//                    new UserAvatar("李四", "宣传部", new ByteArrayImageProvider(p2)));
//            context.put("userList", users);
            // 生成文件
            report.process(context, outputStream);
            //            inputStream.close();
            outputStream.close();

        } catch (Exception e) {
            log.info("生成纪要文件发生异常：<{}>", e.getMessage());
        }
    }
    private IXDocReport ixDocReport;
    private IContext iContext;
    private FieldsMetadata fieldsMetadata;

    /**
     * 生成pdf
     */
    static  void makePdfByXcode(){
        long startTime=System.currentTimeMillis();
        try {
            XWPFDocument document=new XWPFDocument(new FileInputStream(new File("G:\\gpnew\\gp\\src\\main\\resources\\科技创新专项资金引导支持计划项目申报书测试.docx")));
            //    document.setParagraph(new Pa );
            File outFile=new File("G:\\gpnew\\gp\\src\\main\\resources\\测试4.pdf");
            outFile.getParentFile().mkdirs();
            OutputStream out=new FileOutputStream(outFile);
            //    IFontProvider fontProvider = new AbstractFontRegistry();
            PdfOptions options= PdfOptions.create();  //gb2312
            PdfConverter.getInstance().convert(document,out,options);

        }
        catch (  Exception e) {
            e.printStackTrace();
        }
        System.out.println("Generate ooxml.pdf with " + (System.currentTimeMillis() - startTime) + " ms.");
    }


    /**
     * 生成Pdf
     */
    public void createPdf(OutputStream outputStream) {
        try {
            Options options = Options.getTo(ConverterTypeTo.PDF).via(ConverterTypeVia.XWPF);
            this.ixDocReport.setFieldsMetadata(this.fieldsMetadata);
            this.ixDocReport.convert(this.iContext, options, outputStream);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * word(比较胡扯，只支持docx) 转 pdf
     */
    public static void wordConverterToPdf(InputStream source, OutputStream target) throws Exception {
        XWPFDocument doc = new XWPFDocument(source);
        PdfConverter.getInstance().convert(doc, target, null);
    }

    public void createXdocreportToPdf() {
        try {
            //使用远程模板
            InputStream source = this.getClass().getResourceAsStream("/cesshi.docx");
            File outputPdfFile = new File("D:\\BaiduNetdiskDownload\\test.pdf");
            OutputStream target = new FileOutputStream(outputPdfFile);
            PdfOptions options = PdfOptions.create();

            IXDocReport report = XDocReportRegistry
                    .getRegistry()
                    .loadReport(source, TemplateEngineKind.Freemarker);
            // 设置特殊字段
            FieldsMetadata metadata = report.createFieldsMetadata();
            metadata.addFieldAsTextStyling("content", SyntaxKind.Html);
            report.setFieldsMetadata(metadata);
            // 创建内容-text为模版中对应都变量名称
            IContext context = report.createContext();
            context.put("projectName", "年终总结大会");
            context.put("companyName", "2021年3月26日");


            XWPFDocument doc = new XWPFDocument(source);


            // 替换变量占位符 ${xxx}格式，如：${name}
//            replaceInPara(doc, params);

            PdfConverter.getInstance().convert(doc, target, options);
            if (target != null) {
                target.close();
                if (source != null) {
                    source.close();
                }
            }
        } catch (Exception e) {
            log.info("生成纪要文件发生异常：<{}>", e.getMessage());
        }


    }

    /**
     * 替换段落里面的变量
     *
     * @param doc    要替换的文档
     * @param params 参数
     */
    private void replaceInPara(XWPFDocument doc, Map<String, Object> params) {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
        XWPFParagraph para;
        while (iterator.hasNext()) {
            para = iterator.next();
            this.replaceInPara(para, params);
        }
    }

    /**
     * 替换段落里面的变量
     *
     * @param para   要替换的段落
     * @param params 参数
     */
    private void replaceInPara(XWPFParagraph para, Map<String, Object> params) {
        List<XWPFRun> runs;
        Matcher matcher;
        if (matcher(para.getParagraphText()).find()) {
            runs = para.getRuns();
            for (int i = 0; i < runs.size(); i++) {
                XWPFRun run = runs.get(i);
                String runText = run.toString();
                matcher = matcher(runText);
                if (matcher.find()) {
                    while ((matcher = this.matcher(runText)).find()) {
                        runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));
                    }
                    //直接调用XWPFRun的setText()方法设置文本时，在底层会重新创建一个XWPFRun，把文本附加在当前文本后面，
                    //所以我们不能直接设值，需要先删除当前run,然后再自己手动插入一个新的run。
                    para.removeRun(i);
                    para.insertNewRun(i).setText(runText);
                }
            }
        }
    }

    /**
     * 正则匹配字符串
     *
     * @param str
     * @return
     */
    private Matcher matcher(String str) {
        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        return matcher;
    }

    /**
     * 关闭输入流
     *
     * @param is
     */
    private void close(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭输出流
     *
     * @param os
     */
    private void close(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}








